<?php
/* 
	Name: Form2RDF Class
	Author: Keith Alexander
	Description: a collection of methods for converting $_POST arrays into RDF, 
				after 	filtering the array through the Form Filter Object.
	
*/

class Form2RDF{

	
	function array_to_rdfxml($in)
	{
		$rdf='';
		if(is_array($in))
		{
			foreach($in as $k => $v)
			{
				$rdf_about='';
				if(strpos($k, '://'))
				{
					$rdf_about=' rdf:about="'.$k.'"';
					$k='rdf:Description';
				}
				
				// add Language Typing
				if($pos = strpos($k,'@'))
				{
					$lang = substr($k, ($pos+1) );
					$lang_str = ' xml:lang="'.$lang.'"';
					$k = substr($k, 0, $pos);
				}
				else
				{
					$lang_str = '';
				}
				
				// add literal typing
				if($pos = strpos($k,'^^'))
				{
					$dt = substr($k, ($pos+1) );
					$literal_type_str = ' rdf:datatype="'.$dt.'"';
					$k = substr($k, 0, $pos);
				}
				else
				{
					$literal_type_str ='';
				}
				
				
				
				if(is_string($v))
				{
					if(substr($v,0,7)=='http://' || substr($v,0,7)=='mailto:')
					{
						$rdf.= '<'.$k.' rdf:resource="'. $v.'"/>';
					}
					else
					{
						
						$rdf.= '<'.$k.$literal_type_str.$lang_str.'>'.Form2RDF::xmlspecialchars($v) .'</'.$k.'>';
					}
				}
				
				else if(is_array($v)) //$v is an array
				{
					$atts = array();
					foreach(array_keys($v) as $ak)
					{
						if((strpos($ak,'xmlns') === 0 || strtolower($ak)== 'rdf:about') )
						{
							$atts[] = $ak.'="'.$v[$ak].'"';
							unset($v[$ak]);
						}
					}
					$space = (empty($atts))? '':' ';
					
					if(strtolower($k) == 'rdf:li')
					{
						foreach($v as $li)
						{
							$vx =  Form2RDF::array_to_rdfxml($li);
							$rdf.= '<'.$k.$space.implode(" \r\n",$atts).$rdf_about.'>'. $vx .'</'.$k.'>';
						}
					}
					else if(Form2RDF::is_numeric_array($v))
					{
						$inner_rdf = '';
						foreach($v as $list_item)
						{
							if(substr($list_item,0,7)=='http://' || substr($v,0,7)=='mailto:')
							{
								$rdf.="<{$k} ".'rdf:resource="'.$list_item.'"/>';
							}
							else
							{
								$inner_rdf .= Form2RDF::array_to_rdfxml($list_item);								
							}

						}
						if(!empty($inner_rdf)) $rdf.= '<'.$k.$literal_type_str.$lang_str.$space.implode(" \r\n",$atts).$rdf_about.'>'. $inner_rdf .'</'.$k.'>';
					}
					else
					{	
						$vx =  Form2RDF::array_to_rdfxml($v);
						$rdf.= '<'.$k.$literal_type_str.$lang_str.$space.implode(" \r\n",$atts).$rdf_about.'>'. $vx .'</'.$k.'>';
					}
				}
			}
			return $rdf;
		}
		else
		{
			return($in);
		}
	}
	

	
	
	
	function process_post($formpage, &$post, &$formProcessor)
	{
		$processed_post = array();
		$template_post_array = array();
		$simple = "<div>".preg_replace('/<\?.+?(\?>)/','', $formpage)."</div>";
		if(!$simple) $formProcessor->errors[]='Couldn\'t retrieve form page to parse.';
		$p = xml_parser_create();
		xml_parse_into_struct($p, $simple, $vals, $index) or die("couldn't parse xml of form page");
		xml_parser_free($p);
		
		$previous_row_num = -2; //to get the previous row num
		foreach($vals as $r)
		{
			$previous_row_num++;
			if(isset($r['attributes']['NAME'])) //it's (probably) a form element
			{
				parse_str($r['attributes']['NAME'], $out);
				$template_post_array = array_merge_recursive($template_post_array, $out);
				preg_match_all('/([^\[\]]+)/', $r['attributes']['NAME'], $matches);
				
				//this builds up a path to the assoc array element as a string - eg: 'rdf:Rdf[foaf:name]'
					$path = '';
					$keys = array();
					for($x = 0; $x < count($matches[1]); $x++)
					{
						$curr_key = $matches[1][$x];
						$keys[]=$curr_key;
						$path.='["'.$curr_key.'"]';
					}
					
				if(isset($r['attributes']['CLASS'])) //now set the classnames string as the value of the name associative array
				{
					preg_match_all('/f_([a-zA-Z_0-9&;]+)/', $r['attributes']['CLASS'], $m);
					$functions = $m[1];
				}
				else
				{
					$functions = array();
				}
				//get user value to be passed through functions
				eval('$user_value =  $post'.$path.';');
				if(!empty($functions))
				{
					foreach($functions as $f)
					{
						//presumably calls the functions in the order they appear in the class string
						$f = str_replace('&amp;','&', $f); //to allow return-by-ref functions
						$identifier = $vals[$previous_row_num]['value'];
						$user_value = call_user_func(array(&$formProcessor, $f), $user_value, $identifier) or die("No such function as $f");
					}
					//this is really hackish
					//it is a way of getting round the difficulty 
					//of allowing user given values in eval
						$val_ref = '';
						eval('$processed_post'.$path.' =& $val_ref;');
						$val_ref = ($user_value);
						unset($val_ref);
						
				}
				else
				{
						$val_ref = '';
						eval('$processed_post'.$path.' =& $val_ref;');
						$val_ref = ($user_value);
						unset($val_ref);
			
				}
			
			}
		}
		return $processed_post;
	}
	
	function xmlspecialchars($in)
	{
		$in = str_replace('&', '&amp;', $in);
		$in = str_replace('<','&lt;',$in);
		$in = str_replace('>','&gt;',$in);
		return $in;
	}

	function xmlspecialchars_decode($in)//recursive
	{
		if(is_string($in))
		{
				$in = str_replace('&lt;','<',$in);
				$in = str_replace('&gt;','>',$in);
				$in = str_replace('&', '&amp;', $in);
				return $in;
		}
		elseif(is_array($in))
		{
			foreach($in as $k=>$v)
			{
				$in[$k] = Form2RDF::xmlspecialchars_decode($v);
			}
			return $in;
		}
	}
	
	function is_numeric_array($arr) 
	{
	         if (!is_array($arr))
	                 return false;
	 
	         if (count($arr) == 0)
	                 return true;
	 
	         foreach (array_keys($arr) as $key)
	                 if (!is_int($key))
	                         return false;
	 
	         return true;
	 }
	
}
?>